/*
 * Font Style Helper 0.9
 *
 * Copyright (c) 2008 Scott Sadler (ssadler@mashi.org)
 * Liscenced under GPL, see http://www.gnu.org/licenses/gpl.txt
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

(function() {

var fa_control_style = document.createElement('style');
fa_control_style.type = 'text/css';
fa_control_style.textContent = ""+<r><![CDATA[
    .fsh_iface {
        position: absolute;
        width:100%;
        border:2px solid grey;
        font:11px tahoma;
        background-color: #333;
        padding:1px;
        text-align: left;
        color: #EEE;
        width: 300px;
        z-index: 2147483640;
    }
    .fsh_close {
        float: right;
        cursor:pointer;
        width: 14px;
        height: 14px;
        background: url() no-repeat 3px 2px;
    }
    .fsh_title {
        font-family:georgia;
        font-weight:bold;
        background-color: #666;
        cursor:move;
        color: #71FF50;
        text-align:center;
        letter-spacing:0.9px;
        word-spacing: -0.4px;
    }
    .fsh_handle {
        font-weight:bold;
    }
    .fsh_draggable_y {
        cursor:n-resize;
    }
    .fsh_clickable {
        cursor:pointer;
    }
    .fsh_rollout {
        height: 0px;
        overflow: hidden;
        background-color: #444;
    }
    .fsh_font_selectable {
        cursor: pointer;
        padding:1px;
        font-size:12px;
    }
    .fsh_control_layout {
        border-top: 1px solid #666;
        padding:2px 4px;;
        white-space:nowrap;
        overflow:hidden;
    }
    .fsh_bookmark {
        padding-top: 0px;
        border: 1px solid white;
        padding: 0px 5px 4px 5px;
    }
    .fsh_bookmark_legend {
        font-weight: bold;
        border: 1px solid white;
        background-color: #888;
        color: white;
        padding: 1px;
        margin: 0px;
        font: 11px tahoma;
    }
    .fsh_bookmark .fsh_field {
        clear: both;
        padding-top: 2px;
    }
    .fsh_bookmark label {
        display: block;
        padding-top: 2px;
    }
    .fsh_bookmark .fsh_field input[type=text], .fsh_bookmark .fsh_field input[type=checkbox] { float: right; }
    .fsh_bookmark textarea {
        display: block;
        margin: 5px auto;
        width: 90%;
        font-size: 10px;
    }
    .fsh_colortable {
        width: 100%;
        background-color: inherit;
    }
    .fsh_colortable td {
        color: white;
        font-size: 12px;
        width: 12px;
        height: 12px;
        vertical-align: middle;
        background-color: inherit;
    }
    .fsh_color_hex {
        font-family: monospace;
    }
    .fsh_color_name {
        cursor: pointer;
    }
    .fsh_color_pad {
        margin: 1px;
        width: 25px;
    }
    .fsh_about_info {
        white-space: normal;
        text-align: center;
        margin: 5px 0px;
    }
    .fsh_about_info a {
        color: #00BFFF;
        text-decoration: none;
        display: block;
        margin: inherit;
    }
    .fsh_about_info a:hover {
        text-decoration: underline;
    }
]]></r>;
document.getElementsByTagName('head')[0].appendChild(fa_control_style);


var loadFSH = function(src, timeout, nocache) {
    if (nocache) src += '?&_a_a=' + Math.random()
    if (!window['_fsh_script']) {
        var _fsh_script = window['_fsh_script'] = document.createElement('script');
        _fsh_script.src=src;
        document.getElementsByTagName('head')[0].appendChild(_fsh_script);
    }
    var iterations = 0;
    var maxiterations = timeout*1000/10; 
    (function() {
        if (window['_fsh']) window['_fsh']();
        else if (iterations++ > maxiterations)
            alert("FSH load timed out. Try again.\nIf you see this message alot, consider increasing the timeout.\nUrl: "+src+", timeout: "+timeout);
        else window.setTimeout(arguments.callee, 10);
    })();
}

var getBookmarklet = function(src, timeout, nocache) {
    nocache = nocache ? '1' : '0';
    var l = loadFSH + '';
    l = l.replace(/\s+/gm, ' ');
    return 'javascript: (' + l + ')(' + ['"'+src+'"', timeout, nocache].join(',') + ')';
}
        
var fonts =
    ["Arial, Helvetica, sans-serif",
    "'Arial Black', Gadget, sans-serif",
    "'Comic Sans MS', Textile, cursive",
    "'Courier New', Courier, monospace",
    "Georgia, 'Times New Roman', Times, serif",
    "Impact, Charcoal, sans-serif",
    "'Lucida Console', Monaco, monospace",
    "'Lucida Sans Unicode', 'Lucida Grande', sans-serif",
    "'MS Sans Serif', Geneva, sans-serif",
    "'MS Serif', 'New York', serif",
    "'Palatino Linotype', 'Book Antiqua', Palatino, serif",
    "Tahoma, Geneva, sans-serif",
    "'Times New Roman', Times, serif",
    "'Trebuchet MS', Helvetica, sans-serif",
    "Verdana, Geneva, sans-serif"]

var colors = [{hue: 27,name: 'AliceBlue',hex: '#F0F8FF',rgb: [240, 248, 255],hueindex: 0,lum: 247},{hue: 214,name: 'AntiqueWhite',hex: '#FAEBD7',rgb: [250, 235, 215],hueindex: 3,lum: 233},{hue: 360,name: 'Aqua',hex: '#00FFFF',rgb: [0, 255, 255],hueindex: 6,lum: 170},{hue: 340,name: 'Aquamarine',hex: '#7FFFD4',rgb: [127, 255, 212],hueindex: 5,lum: 198},{hue: 360,name: 'Azure',hex: '#F0FFFF',rgb: [240, 255, 255],hueindex: 6,lum: 250},{hue: 239,name: 'Beige',hex: '#F5F5DC',rgb: [245, 245, 220],hueindex: 3,lum: 236},{hue: 212,name: 'Bisque',hex: '#FFE4C4',rgb: [255, 228, 196],hueindex: 3,lum: 226},{hue: 180,name: 'Black',hex: '#000000',rgb: [0, 0, 0],hueindex: 3,lum: 0},{hue: 216,name: 'BlanchedAlmond',hex: '#FFEBCD',rgb: [255, 235, 205],hueindex: 3,lum: 231},{hue: 59,name: 'Blue',hex: '#0000FF',rgb: [0, 0, 255],hueindex: 0,lum: 85},{hue: 91,name: 'BlueViolet',hex: '#8A2BE2',rgb: [138, 43, 226],hueindex: 1,lum: 135},{hue: 180,name: 'Brown',hex: '#A52A2A',rgb: [165, 42, 42],hueindex: 3,lum: 83},{hue: 214,name: 'BurlyWood',hex: '#DEB887',rgb: [222, 184, 135],hueindex: 3,lum: 180},{hue: 1,name: 'CadetBlue',hex: '#5F9EA0',rgb: [95, 158, 160],hueindex: 0,lum: 137},{hue: 270,name: 'Chartreuse',hex: '#7FFF00',rgb: [127, 255, 0],hueindex: 4,lum: 127},{hue: 204,name: 'Chocolate',hex: '#D2691E',rgb: [210, 105, 30],hueindex: 3,lum: 115},{hue: 195,name: 'Coral',hex: '#FF7F50',rgb: [255, 127, 80],hueindex: 3,lum: 154},{hue: 39,name: 'CornflowerBlue',hex: '#6495ED',rgb: [100, 149, 237],hueindex: 0,lum: 162},{hue: 229,name: 'Cornsilk',hex: '#FFF8DC',rgb: [255, 248, 220],hueindex: 3,lum: 241},{hue: 169,name: 'Crimson',hex: '#DC143C',rgb: [220, 20, 60],hueindex: 2,lum: 100},{hue: 360,name: 'Cyan',hex: '#00FFFF',rgb: [0, 255, 255],hueindex: 6,lum: 170},{hue: 59,name: 'DarkBlue',hex: '#00008B',rgb: [0, 0, 139],hueindex: 0,lum: 46},{hue: 360,name: 'DarkCyan',hex: '#008B8B',rgb: [0, 139, 139],hueindex: 6,lum: 92},{hue: 223,name: 'DarkGoldenRod',hex: '#B8860B',rgb: [184, 134, 11],hueindex: 3,lum: 109},{hue: 180,name: 'DarkGray',hex: '#A9A9A9',rgb: [169, 169, 169],hueindex: 3,lum: 169},{hue: 180,name: 'DarkGrey',hex: '#A9A9A9',rgb: [169, 169, 169],hueindex: 3,lum: 169},{hue: 300,name: 'DarkGreen',hex: '#006400',rgb: [0, 100, 0],hueindex: 5,lum: 33},{hue: 236,name: 'DarkKhaki',hex: '#BDB76B',rgb: [189, 183, 107],hueindex: 3,lum: 159},{hue: 120,name: 'DarkMagenta',hex: '#8B008B',rgb: [139, 0, 139],hueindex: 2,lum: 92},{hue: 261,name: 'DarkOliveGreen',hex: '#556B2F',rgb: [85, 107, 47],hueindex: 4,lum: 79},{hue: 213,name: 'Darkorange',hex: '#FF8C00',rgb: [255, 140, 0],hueindex: 3,lum: 131},{hue: 101,name: 'DarkOrchid',hex: '#9932CC',rgb: [153, 50, 204],hueindex: 1,lum: 135},{hue: 180,name: 'DarkRed',hex: '#8B0000',rgb: [139, 0, 0],hueindex: 3,lum: 46},{hue: 194,name: 'DarkSalmon',hex: '#E9967A',rgb: [233, 150, 122],hueindex: 3,lum: 168},{hue: 299,name: 'DarkSeaGreen',hex: '#8FBC8F',rgb: [143, 188, 143],hueindex: 4,lum: 158},{hue: 67,name: 'DarkSlateBlue',hex: '#483D8B',rgb: [72, 61, 139],hueindex: 1,lum: 90},{hue: 360,name: 'DarkSlateGray',hex: '#2F4F4F',rgb: [47, 79, 79],hueindex: 6,lum: 68},{hue: 360,name: 'DarkSlateGrey',hex: '#2F4F4F',rgb: [47, 79, 79],hueindex: 6,lum: 68},{hue: 0,name: 'DarkTurquoise',hex: '#00CED1',rgb: [0, 206, 209],hueindex: 0,lum: 138},{hue: 103,name: 'DarkViolet',hex: '#9400D3',rgb: [148, 0, 211],hueindex: 1,lum: 119},{hue: 147,name: 'DeepPink',hex: '#FF1493',rgb: [255, 20, 147],hueindex: 2,lum: 140},{hue: 13,name: 'DeepSkyBlue',hex: '#00BFFF',rgb: [0, 191, 255],hueindex: 0,lum: 148},{hue: 180,name: 'DimGray',hex: '#696969',rgb: [105, 105, 105],hueindex: 3,lum: 105},{hue: 180,name: 'DimGrey',hex: '#696969',rgb: [105, 105, 105],hueindex: 3,lum: 105},{hue: 29,name: 'DodgerBlue',hex: '#1E90FF',rgb: [30, 144, 255],hueindex: 0,lum: 143},{hue: 180,name: 'FireBrick',hex: '#B22222',rgb: [178, 34, 34],hueindex: 3,lum: 82},{hue: 220,name: 'FloralWhite',hex: '#FFFAF0',rgb: [255, 250, 240],hueindex: 3,lum: 248},{hue: 300,name: 'ForestGreen',hex: '#228B22',rgb: [34, 139, 34],hueindex: 5,lum: 69},{hue: 120,name: 'Fuchsia',hex: '#FF00FF',rgb: [255, 0, 255],hueindex: 2,lum: 170},{hue: 180,name: 'Gainsboro',hex: '#DCDCDC',rgb: [220, 220, 220],hueindex: 3,lum: 220},{hue: 59,name: 'GhostWhite',hex: '#F8F8FF',rgb: [248, 248, 255],hueindex: 0,lum: 250},{hue: 231,name: 'Gold',hex: '#FFD700',rgb: [255, 215, 0],hueindex: 3,lum: 156},{hue: 223,name: 'GoldenRod',hex: '#DAA520',rgb: [218, 165, 32],hueindex: 3,lum: 138},{hue: 180,name: 'Gray',hex: '#808080',rgb: [128, 128, 128],hueindex: 3,lum: 128},{hue: 180,name: 'Grey',hex: '#808080',rgb: [128, 128, 128],hueindex: 3,lum: 128},{hue: 300,name: 'Green',hex: '#008000',rgb: [0, 128, 0],hueindex: 5,lum: 42},{hue: 263,name: 'GreenYellow',hex: '#ADFF2F',rgb: [173, 255, 47],hueindex: 4,lum: 158},{hue: 300,name: 'HoneyDew',hex: '#F0FFF0',rgb: [240, 255, 240],hueindex: 5,lum: 245},{hue: 149,name: 'HotPink',hex: '#FF69B4',rgb: [255, 105, 180],hueindex: 2,lum: 180},{hue: 180,name: 'IndianRed',hex: '#CD5C5C',rgb: [205, 92, 92],hueindex: 3,lum: 129},{hue: 95,name: 'Indigo',hex: '#4B0082',rgb: [75, 0, 130],hueindex: 1,lum: 68},{hue: 239,name: 'Ivory',hex: '#FFFFF0',rgb: [255, 255, 240],hueindex: 3,lum: 250},{hue: 234,name: 'Khaki',hex: '#F0E68C',rgb: [240, 230, 140],hueindex: 3,lum: 203},{hue: 59,name: 'Lavender',hex: '#E6E6FA',rgb: [230, 230, 250],hueindex: 0,lum: 236},{hue: 160,name: 'LavenderBlush',hex: '#FFF0F5',rgb: [255, 240, 245],hueindex: 2,lum: 246},{hue: 270,name: 'LawnGreen',hex: '#7CFC00',rgb: [124, 252, 0],hueindex: 4,lum: 125},{hue: 234,name: 'LemonChiffon',hex: '#FFFACD',rgb: [255, 250, 205],hueindex: 3,lum: 236},{hue: 13,name: 'LightBlue',hex: '#ADD8E6',rgb: [173, 216, 230],hueindex: 0,lum: 206},{hue: 180,name: 'LightCoral',hex: '#F08080',rgb: [240, 128, 128],hueindex: 3,lum: 165},{hue: 360,name: 'LightCyan',hex: '#E0FFFF',rgb: [224, 255, 255],hueindex: 6,lum: 244},{hue: 239,name: 'LightGoldenRodYellow',hex: '#FAFAD2',rgb: [250, 250, 210],hueindex: 3,lum: 236},{hue: 180,name: 'LightGray',hex: '#D3D3D3',rgb: [211, 211, 211],hueindex: 3,lum: 211},{hue: 180,name: 'LightGrey',hex: '#D3D3D3',rgb: [211, 211, 211],hueindex: 3,lum: 211},{hue: 300,name: 'LightGreen',hex: '#90EE90',rgb: [144, 238, 144],hueindex: 5,lum: 175},{hue: 171,name: 'LightPink',hex: '#FFB6C1',rgb: [255, 182, 193],hueindex: 2,lum: 210},{hue: 196,name: 'LightSalmon',hex: '#FFA07A',rgb: [255, 160, 122],hueindex: 3,lum: 179},{hue: 357,name: 'LightSeaGreen',hex: '#20B2AA',rgb: [32, 178, 170],hueindex: 5,lum: 126},{hue: 22,name: 'LightSkyBlue',hex: '#87CEFA',rgb: [135, 206, 250],hueindex: 0,lum: 197},{hue: 30,name: 'LightSlateGray',hex: '#778899',rgb: [119, 136, 153],hueindex: 0,lum: 136},{hue: 30,name: 'LightSlateGrey',hex: '#778899',rgb: [119, 136, 153],hueindex: 0,lum: 136},{hue: 34,name: 'LightSteelBlue',hex: '#B0C4DE',rgb: [176, 196, 222],hueindex: 0,lum: 198},{hue: 239,name: 'LightYellow',hex: '#FFFFE0',rgb: [255, 255, 224],hueindex: 3,lum: 244},{hue: 300,name: 'Lime',hex: '#00FF00',rgb: [0, 255, 0],hueindex: 5,lum: 85},{hue: 300,name: 'LimeGreen',hex: '#32CD32',rgb: [50, 205, 50],hueindex: 5,lum: 101},{hue: 209,name: 'Linen',hex: '#FAF0E6',rgb: [250, 240, 230],hueindex: 3,lum: 240},{hue: 120,name: 'Magenta',hex: '#FF00FF',rgb: [255, 0, 255],hueindex: 2,lum: 170},{hue: 180,name: 'Maroon',hex: '#800000',rgb: [128, 0, 0],hueindex: 3,lum: 42},{hue: 340,name: 'MediumAquaMarine',hex: '#66CDAA',rgb: [102, 205, 170],hueindex: 5,lum: 159},{hue: 59,name: 'MediumBlue',hex: '#0000CD',rgb: [0, 0, 205],hueindex: 0,lum: 68},{hue: 109,name: 'MediumOrchid',hex: '#BA55D3',rgb: [186, 85, 211],hueindex: 1,lum: 160},{hue: 79,name: 'MediumPurple',hex: '#9370D8',rgb: [147, 112, 216],hueindex: 1,lum: 158},{hue: 326,name: 'MediumSeaGreen',hex: '#3CB371',rgb: [60, 179, 113],hueindex: 5,lum: 117},{hue: 67,name: 'MediumSlateBlue',hex: '#7B68EE',rgb: [123, 104, 238],hueindex: 1,lum: 155},{hue: 337,name: 'MediumSpringGreen',hex: '#00FA9A',rgb: [0, 250, 154],hueindex: 5,lum: 134},{hue: 358,name: 'MediumTurquoise',hex: '#48D1CC',rgb: [72, 209, 204],hueindex: 5,lum: 161},{hue: 141,name: 'MediumVioletRed',hex: '#C71585',rgb: [199, 21, 133],hueindex: 2,lum: 117},{hue: 60,name: 'MidnightBlue',hex: '#191970',rgb: [25, 25, 112],hueindex: 1,lum: 54},{hue: 330,name: 'MintCream',hex: '#F5FFFA',rgb: [245, 255, 250],hueindex: 5,lum: 250},{hue: 185,name: 'MistyRose',hex: '#FFE4E1',rgb: [255, 228, 225],hueindex: 3,lum: 236},{hue: 218,name: 'Moccasin',hex: '#FFE4B5',rgb: [255, 228, 181],hueindex: 3,lum: 221},{hue: 216,name: 'NavajoWhite',hex: '#FFDEAD',rgb: [255, 222, 173],hueindex: 3,lum: 216},{hue: 59,name: 'Navy',hex: '#000080',rgb: [0, 0, 128],hueindex: 0,lum: 42},{hue: 219,name: 'OldLace',hex: '#FDF5E6',rgb: [253, 245, 230],hueindex: 3,lum: 242},{hue: 239,name: 'Olive',hex: '#808000',rgb: [128, 128, 0],hueindex: 3,lum: 85},{hue: 258,name: 'OliveDrab',hex: '#6B8E23',rgb: [107, 142, 35],hueindex: 4,lum: 94},{hue: 219,name: 'Orange',hex: '#FFA500',rgb: [255, 165, 0],hueindex: 3,lum: 140},{hue: 195,name: 'OrangeRed',hex: '#FF4500',rgb: [255, 69, 0],hueindex: 3,lum: 108},{hue: 121,name: 'Orchid',hex: '#DA70D6',rgb: [218, 112, 214],hueindex: 2,lum: 181},{hue: 235,name: 'PaleGoldenRod',hex: '#EEE8AA',rgb: [238, 232, 170],hueindex: 3,lum: 213},{hue: 300,name: 'PaleGreen',hex: '#98FB98',rgb: [152, 251, 152],hueindex: 5,lum: 185},{hue: 360,name: 'PaleTurquoise',hex: '#AFEEEE',rgb: [175, 238, 238],hueindex: 6,lum: 217},{hue: 160,name: 'PaleVioletRed',hex: '#D87093',rgb: [216, 112, 147],hueindex: 2,lum: 158},{hue: 217,name: 'PapayaWhip',hex: '#FFEFD5',rgb: [255, 239, 213],hueindex: 3,lum: 235},{hue: 208,name: 'PeachPuff',hex: '#FFDAB9',rgb: [255, 218, 185],hueindex: 3,lum: 219},{hue: 209,name: 'Peru',hex: '#CD853F',rgb: [205, 133, 63],hueindex: 3,lum: 133},{hue: 170,name: 'Pink',hex: '#FFC0CB',rgb: [255, 192, 203],hueindex: 2,lum: 216},{hue: 120,name: 'Plum',hex: '#DDA0DD',rgb: [221, 160, 221],hueindex: 2,lum: 200},{hue: 5,name: 'PowderBlue',hex: '#B0E0E6',rgb: [176, 224, 230],hueindex: 0,lum: 210},{hue: 120,name: 'Purple',hex: '#800080',rgb: [128, 0, 128],hueindex: 2,lum: 85},{hue: 180,name: 'Red',hex: '#FF0000',rgb: [255, 0, 0],hueindex: 3,lum: 85},{hue: 180,name: 'RosyBrown',hex: '#BC8F8F',rgb: [188, 143, 143],hueindex: 3,lum: 158},{hue: 46,name: 'RoyalBlue',hex: '#4169E1',rgb: [65, 105, 225],hueindex: 0,lum: 131},{hue: 204,name: 'SaddleBrown',hex: '#8B4513',rgb: [139, 69, 19],hueindex: 3,lum: 75},{hue: 185,name: 'Salmon',hex: '#FA8072',rgb: [250, 128, 114],hueindex: 3,lum: 164},{hue: 207,name: 'SandyBrown',hex: '#F4A460',rgb: [244, 164, 96],hueindex: 3,lum: 168},{hue: 326,name: 'SeaGreen',hex: '#2E8B57',rgb: [46, 139, 87],hueindex: 5,lum: 90},{hue: 204,name: 'SeaShell',hex: '#FFF5EE',rgb: [255, 245, 238],hueindex: 3,lum: 246},{hue: 198,name: 'Sienna',hex: '#A0522D',rgb: [160, 82, 45],hueindex: 3,lum: 95},{hue: 180,name: 'Silver',hex: '#C0C0C0',rgb: [192, 192, 192],hueindex: 3,lum: 192},{hue: 16,name: 'SkyBlue',hex: '#87CEEB',rgb: [135, 206, 235],hueindex: 0,lum: 192},{hue: 67,name: 'SlateBlue',hex: '#6A5ACD',rgb: [106, 90, 205],hueindex: 1,lum: 133},{hue: 30,name: 'SlateGray',hex: '#708090',rgb: [112, 128, 144],hueindex: 0,lum: 128},{hue: 30,name: 'SlateGrey',hex: '#708090',rgb: [112, 128, 144],hueindex: 0,lum: 128},{hue: 180,name: 'Snow',hex: '#FFFAFA',rgb: [255, 250, 250],hueindex: 3,lum: 251},{hue: 329,name: 'SpringGreen',hex: '#00FF7F',rgb: [0, 255, 127],hueindex: 5,lum: 127},{hue: 26,name: 'SteelBlue',hex: '#4682B4',rgb: [70, 130, 180],hueindex: 0,lum: 126},{hue: 214,name: 'Tan',hex: '#D2B48C',rgb: [210, 180, 140],hueindex: 3,lum: 176},{hue: 360,name: 'Teal',hex: '#008080',rgb: [0, 128, 128],hueindex: 6,lum: 85},{hue: 120,name: 'Thistle',hex: '#D8BFD8',rgb: [216, 191, 216],hueindex: 2,lum: 207},{hue: 188,name: 'Tomato',hex: '#FF6347',rgb: [255, 99, 71],hueindex: 3,lum: 141},{hue: 354,name: 'Turquoise',hex: '#40E0D0',rgb: [64, 224, 208],hueindex: 5,lum: 165},{hue: 120,name: 'Violet',hex: '#EE82EE',rgb: [238, 130, 238],hueindex: 2,lum: 202},{hue: 219,name: 'Wheat',hex: '#F5DEB3',rgb: [245, 222, 179],hueindex: 3,lum: 215},{hue: 180,name: 'White',hex: '#FFFFFF',rgb: [255, 255, 255],hueindex: 3,lum: 255},{hue: 180,name: 'WhiteSmoke',hex: '#F5F5F5',rgb: [245, 245, 245],hueindex: 3,lum: 245},{hue: 239,name: 'Yellow',hex: '#FFFF00',rgb: [255, 255, 0],hueindex: 3,lum: 170},{hue: 258,name: 'YellowGreen',hex: '#9ACD32',rgb: [154, 205, 50],hueindex: 4,lum: 136}];
colors.colorSort = function() {
    var sorters = arguments;
    var sorter = function(a, b) {
        for (var i=0; i<sorters.length; i++) {
            var sorter = sorters[i];
            if (a[sorter]<b[sorter]) return -1;
            if (a[sorter]>b[sorter]) return 1;
        }
        return 0;
    }
    colors.sort(sorter);
}
        
Function.prototype.bind_ = function() {
    var i, fn=this, args1=[], scope=arguments[0] || window;
    for(i=1; i<arguments.length; i++)
    	args1.push(arguments[i]);
    return function() {
        var args2 = [];
        for (var i=0; i<args1.length;i++)
            args2.push(args1[i]);
    	for(i=0; i<arguments.length; i++)
    		args2.push(arguments[i]);
    	return fn.apply(scope, args2);
    }
}

var object_extend = function(dest, src) {
    for (var property in src)
        dest[property] = src[property];
}

var object_beget = function(dest, source) {
    var F = function() {}
    F.prototype = dest;
    F = new F();
    object_extend(F, source);
    return F;
}

var object_as_list = function(o) {
    var l = [];
    for (var i=0; i<o.length; i++) l.push(o[i]);
    return l;
}


function doDrag(mousemove) {
    document.addEventListener('mousemove', mousemove, false);
    var mouseup = function(e) {
        document.removeEventListener('mouseup', arguments.callee, false);
        document.removeEventListener('mousemove', mousemove, false);
    }
    document.addEventListener('mouseup', mouseup, false);
}


var createInterface = function(e) {
    var htmlStr = '<div class="fsh_iface"></div>';
    var iface = getNode(document.body, htmlStr);
    iface.style.left = e.pageX + 'px';
    iface.style.top = e.pageY + 'px';
    iface.events = [];
    iface.registerEvent = function(eventType, target, callback) {
        this.events.push([eventType, target, callback]);
    }
    iface.handleEvent = function(e) {
        for (var i=0; i<this.events.length; i++) {
            if (e.target == this.events[i][1]) {
                // we prevent the default action (start a selection) if the target is a handle,
                // regardless whether this is the event we want to capture. 
                // A mousedown event always occurs before a click event.
                e.preventDefault();
                if (e.type == this.events[i][0]) {
                    e.stopPropagation();
                    this.events[i][2](e);
                    return;
                }
            }
        }
    }
    var callback = function(e) { iface.handleEvent(e); }
    iface.addEventListener('click', callback, true);
    iface.addEventListener('mousedown', callback, true);
    return iface;
}


var getNode = function(par, htmlStr) {
    var el = document.createElement('div');
    el.innerHTML = htmlStr;
    return par.appendChild(el.firstChild);
}

var getNodes = function(par, htmlStr) {
    /* Take a parent node, some HTML and a list of nodes to identify.
     * Add the html to the parent node and return a dictionary with node handles */
    var el = document.createElement('div');
    el.innerHTML = htmlStr;
    var args = [null]; // null becaue the first element will be our parent
    for (var i=2;i<arguments.length;i++) args.push(arguments[i]);
    var elems = {};
    var k = null;
    
    (function(child) {
        if (['#text', 'BR'].indexOf(child.nodeName) != -1) return;
        if (k = args.shift()) elems[k] = child;
        if (child.hasChildNodes()) object_as_list(child.childNodes).map(arguments.callee);
    })(el);
    object_as_list(el.childNodes).map(function(node) {
        par.appendChild(node);
    });
    return elems;
}

var cssGetValue = function(propertyName, target, raw) {
    var str = window.getComputedStyle(target,null).getPropertyValue(propertyName);
    if (raw) return str;
    var m = /(\-?[\d\.]+)?(.*)/.exec(str);
    return m ?
        [m[1] && (m[1]*1) || null, m[2]] :
        [null, null];
}

// this function allows the user to select an element and executes a callback
var fsh_startselector = function(clickCallback) {
    var sel = function(e) {
    	var self = arguments.callee;
    	e.stopPropagation();
    	if (typeof(self.target) != 'object') {
    		document.addEventListener('click',function(e) {
    			e.stopPropagation();
    			e.preventDefault();
    			document.removeEventListener('click',arguments.callee,true);
    			document.removeEventListener('mousemove',self,false);
    			self.target.style.outline = 'none';
    			self.target = false;
    			clickCallback(e,e.target);
    		},true)
    		self.target = false;
    	}

    	if (self.target != e.target) {
    		self.target = e.target;
    		self.target.addEventListener('mouseout',function(e) {
    			e.target.style.outline = 'none';
    			e.target.removeEventListener('mouseout',arguments.callee,false);
    		},false);
    		self.target.style.outline = "orangered solid 2px";
    	}
    }

    document.addEventListener('mousemove',sel,false);
}



var rollout = function(el_rollout, prepare, cleanup) {
    object_extend(el_rollout, {
        pxSpeed: 15,
        roll: function(tH, finCallback) {
            if (this.rollInterval) window.clearInterval(rollInterval);
            this.rollInterval = rollInterval = window.setInterval(function() {
                var oH = this.offsetHeight;
                if (tH != oH) {
                    var m = tH - oH;
                    m = m>0 ? (m > this.pxSpeed ? this.pxSpeed : m) :
                              (m < -this.pxSpeed ? -this.pxSpeed : m);
                    this.style.height = (m + oH) + 'px';
                } else {
                    window.clearInterval(rollInterval);
                    finCallback && finCallback();
                }
            }.bind_(this), 1);

        },
        // callbacks are separate from prepare/cleanup and get executed after rollout is done
        show: function(callback) {
            this.roll(this.scrollHeight, callback);
        },
        hide: function(callback) {
            this.roll(0, callback);
        },
    });
    
    // a general event handler to automatically show/hide.
    return function(prepare, cleanup, e) {
        if (this.offsetHeight > 0) {
            this.hide(cleanup);
        } else {
            prepare && prepare();
            this.show();
        }
    }.bind_(el_rollout, prepare, cleanup);
}





var Control = {
    interface_contribute: function(iface, target) {
        var htmlStr = '<div class="fsh_control_layout">' +
                '<span class="fsh_handle fsh_'+this.type+'">'+this.propertyName+': </span>' +
                '<span>'+this.current(target, true)+'</span></div>';
        var nodes = getNodes(iface, htmlStr, 'layout', 'handle', 'value');
        nodes.value = nodes.value.firstChild;
        return nodes;

    },
    current: function(target, join) {
        return cssGetValue(this.propertyName, target, join);
    },
}

var Control_title = {
    contribute: function(iface, target) {
        var el_title = getNode(iface, '<div class="fsh_title">Font Style Helper</div>');
        var mousedown = function(e) {
            var left = e.pageX - iface.offsetLeft;
            var top = e.pageY - iface.offsetTop;
            doDrag(function(e) {
                iface.style.left = (e.pageX - left) + 'px';
                iface.style.top = (e.pageY - top) + 'px';
            });
        }
        iface.registerEvent('mousedown', el_title, mousedown);
    }
}

var Control_close = {
    contribute: function(iface, target) {
        var el_close = getNode(iface, '<div class="fsh_close"></div>');
        var fClose = function() {
            document.body.removeChild(iface);
        }
        iface.registerEvent('click', el_close, fClose);
        var handleKey = function(e) {
            if (e.keyCode == e.DOM_VK_ESCAPE) {
                document.removeEventListener('keydown', arguments.callee, false);
                fClose();
            }
        }
        document.addEventListener('keydown', handleKey, false);
    }
}



var Control_draggable_y = object_beget(Control, {
    type: 'draggable_y',
    contribute: function(iface, target) {
        var elems = this.interface_contribute(iface, target);
        var unit = this.unit || 'px';
        var mousedown = function(e) {
            var startVal = this.current(target);
            var startY = e.screenY;
            var drag = function(e) {
                var diffY = e.screenY - startY;
                var newVal = startVal[0] + (diffY * this.modifier);
                var newVal = Math.round(newVal*this.rounder)/this.rounder;
                target.style[this.propertyNameDOM] = elems.value.data = newVal + unit;
            }.bind_(this);
            doDrag(drag);
        }.bind_(this);
        iface.registerEvent('mousedown', elems.handle, mousedown);
    },
});

var Control_fontSize = object_beget(Control_draggable_y, {
    propertyName: 'font-size',
    propertyNameDOM: 'fontSize',
    modifier: 0.2,
    rounder: 2,
});

var Control_letterSpacing = object_beget(Control_draggable_y, {
    propertyName: 'letter-spacing',
    propertyNameDOM: 'letterSpacing',
    modifier: 0.02,
    rounder: 20,
});

var Control_wordSpacing = object_beget(Control_draggable_y, {
    propertyName: 'word-spacing',
    propertyNameDOM: 'wordSpacing',
    modifier: 0.1,
    rounder: 10,
});

var Control_lineHeight = object_beget(Control_draggable_y, {
    propertyName: 'line-height',
    propertyNameDOM: 'lineHeight',
    modifier: 0.005,
    rounder: 100,
    unit: 'em',
    current: function(target, join) {
        var cur_lh = cssGetValue('line-height', target);
        var r = null;
        if (cur_lh[1] == 'px') {
            // need to get font size to compute em
            var cur_fs = Control_fontSize.current(target);
            if (cur_fs[1] == 'px') {
                r = [(cur_lh[0]/cur_fs[0]), 'em'];
            }
        } else if (cur_lh[1] == 'em') {
            r = cur_lh;
        } else {
            log('oh shit, couldnt get current line height in em');
            r = [1.2, 'em'];
        }
        return join ? r[0]+r[1] : r;
    },
});



var Control_fontFamily = object_beget(Control, {
    type: 'clickable',
    propertyName: 'font-family',
    propertyNameDOM: 'fontFamily',
    contribute: function(iface, target) {
        var elems = this.interface_contribute(iface, target);
        elems.fontlist = getNode(elems.layout, '<div class="fsh_rollout"></div>');

        var selectFont = function(fontStr) {
            object_as_list(elems.fontlist).map(function(el_font) {
                el_font.style.color = (el_font.fontStr == fontStr) ? 'yellow' : '';
            });
            elems.value.data = fontStr;
            target.style.fontFamily = fontStr;
        }
        
        function addFont(fontStr) {
            var el_font = getNode(elems.fontlist, '<div class="fsh_font_selectable"> </div>');
            el_font.firstChild.data = fontStr.replace(/'/g,"");
            el_font.fontStr = fontStr;
            el_font.style.fontFamily = fontStr;
            return el_font;
        }
        
        var prepare = function() {
            var curFont = this.current(target, true).replace(/\,/g, ', ');
            if (fonts.indexOf(curFont) < 0) {
                addFont(curFont);
                fonts.push(curFont);
            }
            selectFont(curFont);
        }.bind_(this);

        var fontClick = function(e) {
            if (e.target.fontStr) selectFont(e.target.fontStr);
        }
        elems.fontlist.addEventListener('click', fontClick, true);

        fonts.map(addFont);
        var click = rollout(elems.fontlist, prepare, function(){});
        iface.registerEvent('click', elems.handle, click);
    },
});


var Control_fontWeight = object_beget(Control, {
    type: 'clickable',
    propertyName: 'font-weight',
    propertyNameDOM: 'fontWeight',
    current: function(target) {
        var cur = cssGetValue('font-weight', target, true);
        if (400 == cur) cur = 'normal';
        return cur;
    },
    contribute: function(iface, target) {
        var elems = this.interface_contribute(iface, target);
        var click = function() {
            var curVal = this.current(target, true);
            var newVal = curVal == 'bold' ? 'normal' : 'bold';
            elems.value.data = target.style.fontWeight = newVal;
        }.bind_(this);
        iface.registerEvent('click', elems.handle, click);
    },
});

var Control_fontStyle = object_beget(Control, {
    type: 'clickable',
    propertyName: 'font-style',
    propertyNameDOM: 'fontStyle',
    contribute: function(iface, target) {
        var elems = this.interface_contribute(iface, target);
        var values = ['normal','italic','oblique'];
        var click = function(e) {
            var cur = this.current(target, true);
            var index = values.indexOf(this.current(target, true));
            index = ((1 + index)%values.length);
            elems.value.data = target.style.fontStyle = values[index];
        }.bind_(this);
        iface.registerEvent('click', elems.handle, click);
    },
});

var Control_color = object_beget(Control, {
    type: 'clickable',
    propertyName: 'color',
    propertyNameDOM: 'color',
    current: function(target) {
        var cur = cssGetValue('color', target, true);
        if (0 == cur.indexOf('rgb(')) {
            var rgb = /rgb.(\d+), ?(\d+), ?(\d+)\)/.exec(cur).slice(1);
            return '#' + rgb.map(function(c) {
                var hex = (c*1).toString(16);
                return (hex.length == 1) ? '0' + hex : hex;
            }).join('').toUpperCase();
        }
        return cur;
    },
    contribute: function(iface, target) {
        var elems = this.interface_contribute(iface, target);
        var roll = getNode(elems.layout, '<div class="fsh_rollout"></div>');
        var cont = getNode(roll, '<div style="height: 150px; overflow: auto; display: none;"></div>');
        var colortable = getNode(cont, '<table class="fsh_colortable" cellpadding="0" cellspacing="0"></table>');
        colors.colorSort('hueindex', 'lum');
        for (var r=0;r<colors.length;r++) {
            var c = colors[r];
            if (-1 != c.name.indexOf('Gray')) continue;
            var row = colortable.appendChild(document.createElement('tr'));
            var cellsHTML = ['<td class="fsh_color_name">&nbsp;'+c.name+'</td>',
                             '<td class="fsh_color_hex">'+c.hex+'</td>',
                             '<td><div class="fsh_color_pad" style="background-color: '+c.hex+';">&nbsp;</div></td>'].join('');
            row.innerHTML = cellsHTML;
            row.c = c;
        }
        var setColor = function(c) {
            elems.value.data = c.hex;
            object_as_list(colortable.childNodes).map(function(row) {
                if (row.c == c) {
                    target.style.color = c.hex;
                    row.style.backgroundColor = 'grey';
                } else {
                    row.style.backgroundColor = '';
                }
            });
        }
            
        var colorClick = function(e) {
            if (e.target.className == "fsh_color_hex") return; // the hex code should not be clickable
            var target = e.target;
            for (var i=0; i<2; i++) {
                target = target.parentNode;
                if (target.nodeName.toLowerCase() == 'tr') setColor(target.c);
            }
        }
        colortable.addEventListener('click', colorClick, true);
        
        var roll_prep = function() { cont.style.display = 'block'; }
        var roll_clean = function() { cont.style.display = 'none'; }

        var click = rollout(roll, roll_prep, roll_clean);
        iface.registerEvent('click', elems.handle, click);
    },
});








var Control_about = object_beget(Control, {
    type: 'clickable',
    contribute: function(iface, target) {
        var htmlStr = [
        '<div class="fsh_control_layout">',
            '<span class="fsh_handle fsh_clickable">About</span>',
            '<div class="fsh_rollout">',
                '<div class="fsh_about_info">',
                    'Font Style Helper is liscenced under the GPL. See the source code for details.',
                    '<br />',
                    '<a target="_blank" href="http://code.google.com/p/font-style-helper/">Project Homepage</a>',
                '</div>',
                '<fieldset class="fsh_bookmark">',
                    '<legend class="fsh_bookmark_legend">Create Bookmarklet</legend>',
                    '<div class="fsh_field">',
                        '<input type="text" />',
                        '<label>URL to fsh.js:</label>',
                    '</div>',
                    '<div class="fsh_field">',
                        '<input type="text" />',
                        '<label>Timeout in seconds:</label>',
                    '</div>',
                    '<div class="fsh_field">',
                        '<input type="checkbox" />',
                        '<label>Prevent Cacheing:</label>',
                    '</div>',
                    '<div class="fsh_field">',
                        '<input type="button" value="Create" />',
                    '</div>',
                    '<textarea></textarea>',
        '</fieldset></div></div>'].join('');
        var elems = getNodes(iface, htmlStr,
                'layout', 'handle', 'rollout', null, null,
                'form', null, null, 'i_src', null,
                null, 'i_timeout', null, null, 'i_nocache',
                null, null, 'i_create', 'i_output');

        elems.i_create.onclick = function(e) {
            var timeout = elems.i_timeout.value;
            var src = elems.i_src.value;
            var nocache = elems.i_nocache.checked;
            var error = null;
            if (isNaN(timeout*1) || (Math.floor(timeout) < 1 || Math.floor(timeout) > 30)) {
                error = 'Invalid timeout, should be a whole number between 1 and 30';
            } else if (0 != elems.i_src.value.toLowerCase().indexOf('http')) {
                error = 'URL seems invalid (should start with http)';
            }
            var callback = null;
            if (error) {
                elems.i_output.style.color = 'red';
                elems.i_output.value = error;
            } else {
                elems.i_output.style.color = 'black';
                elems.i_output.value = getBookmarklet(src, timeout, nocache);
                callback = function() {
                    elems.i_output.focus();
                    elems.i_output.select();
                }
            }
            elems.i_output.style.display = 'block';
            elems.rollout.show(callback);
        }

        var prepare = function() {
            elems.i_src.value = window['_fsh_script'] ? window['_fsh_script'].src : '';
            elems.i_timeout.value = 3;
            elems.i_output.style.display = 'none';
        }
        var click = rollout(elems.rollout, prepare, function(){});
        iface.registerEvent('click', elems.handle, click);
    },
});

var controls = [Control_close,
                Control_title,
                Control_fontSize,
                Control_letterSpacing,
                Control_wordSpacing,
                Control_lineHeight,
                Control_fontFamily,
                Control_fontWeight,
                Control_fontStyle,
                Control_color,
                Control_about];

window['_fsh'] = function() {
    fsh_startselector(function(e, target) {
        var iface = createInterface(e);
        controls.map(function(c) {
            c.contribute(iface, target);
        });
    });
}

})();

